package pattern.controller;


import cn.hutool.core.date.DatePattern;
import cn.hutool.core.text.StrPool;
import cn.hutool.core.util.RandomUtil;
import cn.hutool.core.util.StrUtil;
import com.alibaba.fastjson.JSON;
import io.minio.GetObjectResponse;
import io.swagger.annotations.Api;
import io.swagger.annotations.ApiOperation;
import lombok.RequiredArgsConstructor;
import org.apache.commons.io.IOUtils;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.*;
import org.springframework.web.multipart.MultipartFile;
import pattern.annontations.Menu;
import pattern.annontations.Secure;
import pattern.minio.MinioTool;
import pattern.result.ResponseData;
import pattern.result.ResponseResultStatus;
import pattern.utils.CollectionUtil;

import javax.servlet.ServletOutputStream;
import javax.servlet.http.HttpServletResponse;
import java.net.URLEncoder;
import java.nio.charset.StandardCharsets;
import java.util.Date;

/**
 * @author Simon
 */
@Api(tags = "文件操作")
@RestController
@RequestMapping("/file")
@RequiredArgsConstructor(onConstructor_ = @Autowired)
@Secure
@Menu(verify = false, menuUri = "file", menuName = "file")
public class FileController {

    //XXX 用云服务最好
    private final MinioTool minioTool;

    @Secure(actionNote = "file", actionName = "add", actionUri = "file_add")
    @ApiOperation("上传一个文件")
    @PostMapping(value = "/upload")
    public ResponseData fileupload(@RequestParam(value = "file") @RequestPart(value = "file") MultipartFile file, @RequestParam(required = false) String fileName, @RequestParam(required = false) String bucket) throws Exception {
        if (StringUtils.isBlank(bucket)) {
            bucket = "common";
        }
        if (StringUtils.isBlank(fileName)) {
            fileName = file.getOriginalFilename();
        }
        minioTool.createBucket(bucket);
        var response = minioTool.uploadFile(file.getInputStream(), bucket, StrPool.SLASH + DatePattern.PURE_DATE_FORMAT.format(new Date()) + StrPool.SLASH + StrUtil.toString(RandomUtil.getRandom().nextInt(0, 1000)).concat(StrPool.DASHED).concat(fileName));
        var path = StrPool.SLASH.concat(bucket).concat(StrPool.SLASH).concat(response.object());
        var responseData = new ResponseData<String>(ResponseResultStatus.SUCCESS);
        responseData.setData(path);
        return responseData;
    }

    @Secure(actionNote = "file", actionName = "add", actionUri = "file_add")
    @ApiOperation("上传指定位置文件")
    @PostMapping(value = "/uploadPath")
    public ResponseData uploadPath(@RequestParam(value = "file") @RequestPart(value = "file") MultipartFile file, String bucket, String fileName, String path) throws Exception {
        minioTool.createBucket(bucket);
        var response = minioTool.uploadFile(file.getInputStream(), bucket, StrPool.SLASH + path.concat(fileName));
        var filePath = StrPool.SLASH.concat(bucket).concat(StrPool.SLASH).concat(response.object());
        var responseData = new ResponseData<String>(ResponseResultStatus.SUCCESS);
        responseData.setData(filePath);
        return responseData;
    }

    @Secure(actionNote = "file", actionName = "search", actionUri = "file_list")
    @ApiOperation("列出所有的桶")
    @RequestMapping(value = "/listBuckets", method = RequestMethod.GET)
    public ResponseData listBuckets() throws Exception {
        return new ResponseData<>(minioTool.listBuckets());
    }

    @Secure(actionUri = "file_list")
    @ApiOperation("递归列出一个桶中的所有文件和目录")
    @RequestMapping(value = "/listFiles", method = RequestMethod.GET)
    public ResponseData listFiles(@RequestParam String bucket) throws Exception {
        return new ResponseData<>(minioTool.listFiles(bucket));
    }

    @Secure(value = -1, actionUri = "file_list")
    @ApiOperation("下载一个文件")
    @RequestMapping(value = "/file_download", method = RequestMethod.GET)
    public void downloadFile(@RequestParam String objectName,
                             HttpServletResponse response) throws Exception {
        objectName = objectName.substring(1);
        String bucket = objectName.substring(0, objectName.indexOf(StrPool.SLASH));
        objectName = objectName.replaceFirst(bucket, "");
        GetObjectResponse download = minioTool.download(bucket, objectName);
        ServletOutputStream output = response.getOutputStream();
        response.setHeader("Content-Disposition", "attachment;filename=" + URLEncoder.encode(objectName.substring(objectName.lastIndexOf("/") + 1), StandardCharsets.UTF_8));
        response.setContentType("application/octet-stream");
        response.setCharacterEncoding("UTF-8");
        var headers = download.headers();
        var toMultimap = headers.toMultimap();
        response.setHeader("other", JSON.toJSONString(toMultimap));
        var strings = toMultimap.get("content-length");
        if(CollectionUtil.isNotEmpty(strings)){
            response.setHeader("Content-Length", strings.get(0));
        }
        IOUtils.copy(download, output);
    }

    @Secure(actionNote = "file", actionName = "delete", actionUri = "delete_list")
    @ApiOperation("删除一个文件")
    @RequestMapping(value = "/deleteFile", method = RequestMethod.GET)
    public ResponseData<Boolean> deleteFile(@RequestParam(required = false) String bucket, @RequestParam String objectName) throws Exception {
        if (StringUtils.isBlank(bucket)) {
            bucket = "common";
        }
        if (objectName.contains(bucket)) {
            objectName = objectName.replace(StrPool.SLASH.concat(bucket), "");
        }
        minioTool.deleteObject(bucket, objectName);
        return new ResponseData<>(Boolean.TRUE);
    }

    @Secure(actionUri = "delete_list")
    @ApiOperation("删除一个桶")
    @RequestMapping(value = "/deleteBucket", method = RequestMethod.GET)
    public ResponseData<Boolean> deleteBucket(@RequestParam String bucket) throws Exception {
        minioTool.deleteBucket(bucket);
        return new ResponseData<>(Boolean.TRUE);
    }
}